#include "bsp_i2c.h"
#include "bsp_mlx90614.h"
#include "esp_log.h"
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"

static const char *TAG = "main";

// 全局变量
static bsp_mlx90614_handle_t g_mlx90614_handle;
static bool                  g_sensor_initialized = false;

// 温度数据结构
typedef struct {
    float ambient_temp;
    float object1_temp;
    bool  data_valid;
} temperature_data_t;

// 全局温度数据和同步机制
static temperature_data_t g_temp_data = {0};
static SemaphoreHandle_t  g_temp_mutex = NULL;  // 互斥信号量保护数据
static SemaphoreHandle_t  g_data_ready = NULL;  // 二进制信号量通知数据就绪

// MLX90614读取任务 - 使用信号量同步数据
void mlx90614_read_task(void *pvParameters)
{
    float    ambient_temp, obj1_temp, obj2_temp;
    uint32_t error_count = 0;

    while (1)
    {
        if (!g_sensor_initialized)
        {
            vTaskDelay(pdMS_TO_TICKS(1000));
            continue;
        }

        // 读取所有温度
        esp_err_t ret = bsp_mlx90614_get_temperatures(&g_mlx90614_handle, &ambient_temp, &obj1_temp, &obj2_temp);

        // 获取互斥信号量保护数据
        if (xSemaphoreTake(g_temp_mutex, portMAX_DELAY) == pdTRUE)
        {
            if (ret == ESP_OK)
            {
                // 更新全局温度数据
                g_temp_data.ambient_temp = ambient_temp;
                g_temp_data.object1_temp = obj1_temp;
                g_temp_data.data_valid   = true;

                // 重置错误计数
                error_count = 0;
            }
            else
            {
                error_count++;
                
                // 如果连续错误过多，标记数据无效
                if (error_count >= 5)
                {
                    g_temp_data.data_valid = false;
                    error_count = 0; // 重置错误计数
                }
            }

            // 释放互斥信号量
            xSemaphoreGive(g_temp_mutex);

            // 如果数据有效，通知显示任务
            if (ret == ESP_OK)
            {
                xSemaphoreGive(g_data_ready);
            }
        }

        // 等待1秒后再次测量
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

// 显示任务 - 使用信号量等待数据就绪
void display_task(void *pvParameters)
{
    const char *task_tag = "display_task";
    uint32_t    display_count = 0;
    temperature_data_t local_temp_data;

    ESP_LOGI(task_tag, "显示任务启动");

    while (1)
    {
        // 等待数据就绪信号量（最多等待5秒）
        if (xSemaphoreTake(g_data_ready, pdMS_TO_TICKS(5000)) == pdTRUE)
        {
            // 获取互斥信号量保护数据
            if (xSemaphoreTake(g_temp_mutex, portMAX_DELAY) == pdTRUE)
            {
                // 复制数据到本地变量
                local_temp_data = g_temp_data;
                
                // 释放互斥信号量
                xSemaphoreGive(g_temp_mutex);

                display_count++;
                
                if (local_temp_data.data_valid)
                {
                    printf("\n");
                    printf("========================================\n");
                    printf("        温度测量结果 (第 %lu 次)\n", display_count);
                    printf("========================================\n");
                    printf("环境温度:      %.2f°C\n", local_temp_data.ambient_temp);
                    printf("物体温度1:     %.2f°C\n", local_temp_data.object1_temp);
                    printf("========================================\n");
                    printf("\n");
                }
                else
                {
                    printf("\n");
                    printf("========================================\n");
                    printf("        温度测量结果 (第 %lu 次)\n", display_count);
                    printf("========================================\n");
                    printf("❌ 传感器数据无效\n");
                    printf("========================================\n");
                    printf("\n");
                }
            }
        }
        else
        {
            // 超时，显示等待状态
            printf("\n");
            printf("========================================\n");
            printf("        等待传感器数据...\n");
            printf("========================================\n");
            printf("\n");
        }
    }
}

void app_main(void)
{
    // 设置日志级别为调试
    esp_log_level_set("*", ESP_LOG_VERBOSE);
    esp_log_level_set("bsp_mlx90614", ESP_LOG_VERBOSE);

    ESP_LOGI(TAG, "红外温度测量系统启动");

    // 创建信号量
    g_temp_mutex = xSemaphoreCreateMutex();
    if (g_temp_mutex == NULL)
    {
        ESP_LOGE(TAG, "创建互斥信号量失败");
        return;
    }

    g_data_ready = xSemaphoreCreateBinary();
    if (g_data_ready == NULL)
    {
        ESP_LOGE(TAG, "创建二进制信号量失败");
        return;
    }

    i2c_master_bus_handle_t bus_handle;
    i2c_master_dev_handle_t i2c_dev_handle;

    // 初始化I2C总线
    esp_err_t ret = bsp_i2c_init(&bus_handle, &i2c_dev_handle);
    if (ret != ESP_OK)
    {
        ESP_LOGE(TAG, "I2C初始化失败");
        return;
    }

    // 配置MLX90614传感器
    bsp_mlx90614_config_t mlx90614_config = BSP_MLX90614_CONFIG_DEFAULT();

    // 初始化MLX90614传感器
    ret = bsp_mlx90614_init(bus_handle, &mlx90614_config, &g_mlx90614_handle);
    if (ret != ESP_OK)
    {
        ESP_LOGE(TAG, "MLX90614初始化失败");
        return;
    }

    g_sensor_initialized = true;
    ESP_LOGI(TAG, "系统初始化完成");

    // 创建MLX90614读取任务
    BaseType_t task_ret = xTaskCreate(mlx90614_read_task,   // 任务函数
                                      "mlx90614_read_task", // 任务名称
                                      4096,                 // 栈大小
                                      NULL,                 // 任务参数
                                      5,                    // 任务优先级
                                      NULL                  // 任务句柄
    );

    if (task_ret != pdPASS)
    {
        ESP_LOGE(TAG, "创建MLX90614读取任务失败");
        return;
    }

    // 创建显示任务
    task_ret = xTaskCreate(display_task,   // 任务函数
                           "display_task", // 任务名称
                           4096,           // 栈大小
                           NULL,           // 任务参数
                           configMAX_PRIORITIES - 1, // 最高优先级
                           NULL            // 任务句柄
    );

    if (task_ret != pdPASS)
    {
        ESP_LOGE(TAG, "创建显示任务失败");
        return;
    }

    ESP_LOGI(TAG, "所有任务已创建完成");

    // 主任务可以继续执行其他工作
    while (1)
    {
        ESP_LOGI(TAG, "主任务运行中...");
        vTaskDelay(pdMS_TO_TICKS(10000)); // 每10秒打印一次
    }
}